﻿#include <Sys\RenderUnit\SysRenderDatagram\TEXTURE2DRD.HPP>
#include <Render\Render_Win32\Render_Win32_D3D\RENDER_WIN32_D3D9.HPP>
#include <Sys\RenderUnit\SysDatagramDisposal_D3D\VERTEXREGISTRYDDD3D9.HPP>
#include <Sys\RenderUnit\SysDatagramDisposal_D3D\STAGEDDD3D9.HPP>
//#include <Sys\RenderUnit\SYSDDCLASSID.HPP>
#include <d3dx9.h>

using namespace CxxlMan;
using namespace Cxxl3D;

// 定義在 Texture.cpp
extern bool cxxlFASTCALL AutoTexCoordIndexMode(char Mode,LPDIRECT3DDEVICE9 pDEVICE9, const Smart_Ptr<IStageDDD3D9> IStageDDD3D9_Arg);
extern void TextureAddrMode(unsigned char Mode, unsigned int RGBA, LPDIRECT3DDEVICE9 pDEVICE9, const Smart_Ptr<IStageDDD3D9> IStageDDD3D9_Arg);
extern void TextureMipmapMode(unsigned char Mode, LPDIRECT3DDEVICE9 pDEVICE9, const Smart_Ptr<IStageDDD3D9> IStageDDD3D9_Arg);
extern void cxxlFASTCALL BlendMode(unsigned char BlendMode, LPDIRECT3DDEVICE9 pDEVICE9, const Smart_Ptr<IStageDDD3D9> IStageDDD3D9_Arg);

// IDatagramDisposal 寄存在 IDepositStore 的資料
class CDDDeposit:public IDDDeposit
{
  LPDIRECT3DTEXTURE9 m_pTexture;

  // 取得實作類別，為了避免轉形太花時間
  virtual void *GetInstance()
  {
    return this;
  }
public:
  // Constructor
  CDDDeposit(LPDIRECT3DTEXTURE9 pTexture)
  {
    m_pTexture = pTexture;
  }

  // Destructor
  virtual ~CDDDeposit()
  {
    if(m_pTexture)
      m_pTexture->Release();
  }

  LPDIRECT3DTEXTURE9 GetTextureID() const
  {
    return m_pTexture;
  }

};


static void cxxlFASTCALL TextureMatrix(const CSmart_Ptr<const C3DMatrix4x4> &TextureMatrix_Arg, LPDIRECT3DDEVICE9 pDEVICE9, const Smart_Ptr<IStageDDD3D9> IStageDDD3D9_Arg)
{
  if(TextureMatrix_Arg.isNULL() == false)
  {
    C3DMatrix4x4 vTextureMatrix = *TextureMatrix_Arg;
    vTextureMatrix.m_Vec2 = vTextureMatrix.m_Vec3;
    pDEVICE9->SetTransform( (D3DTRANSFORMSTATETYPE)(D3DTS_TEXTURE0 + IStageDDD3D9_Arg->GetStage()), (D3DMATRIX *) &vTextureMatrix);
    pDEVICE9->SetTextureStageState(IStageDDD3D9_Arg->GetStage(), D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT2); // 讓 Texture Matrix 生效
  }
  else
    pDEVICE9->SetTextureStageState(IStageDDD3D9_Arg->GetStage(), D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE); // 讓 Texture Matrix 失效
}



class CTextureDD_2D_D3D9:public IDatagramDisposal_D3d9, public ITextureBridge
{
  Smart_Ptr<IStageDDD3D9> m_IStageDDD3D9_Ptr;
  Smart_Ptr<IVertexRegistryDDD3D9> m_IVertexRegistryDDD3D9_Ptr;

  virtual bool cxxlFASTCALL Exec(const Smart_Ptr<IRenderDatagramDisposalCenterD3d> &IRenderDatagramDisposalCenterD3d_Arg,
    const Smart_Ptr<IRenderDatagram> &IRenderDatagram_Arg, LPDIRECT3DDEVICE9 pDEVICE9)
  {
    // 第一次被叫用才會取得
    if(m_IStageDDD3D9_Ptr.isNULL())
      m_IStageDDD3D9_Ptr = Smart_Cast<IStageDDD3D9>(IRenderDatagramDisposalCenterD3d_Arg->GetIDatagramDisposal_D3d9(IStageD3D9_ClassID));

    // 第一次被叫用才會取得
    if(m_IVertexRegistryDDD3D9_Ptr.isNULL())
      m_IVertexRegistryDDD3D9_Ptr = Smart_Cast<IVertexRegistryDDD3D9>(IRenderDatagramDisposalCenterD3d_Arg->GetIDatagramDisposal_D3d9(IVertexRegistryD3D9_ClassID));

    Lock(IRenderDatagram_Arg);

    Smart_Ptr<ITextureRD_2D> ITextureRD_2D_Ptr = (ITextureRD_2D*)GetDefaultInterface(IRenderDatagram_Arg);
    Smart_Ptr<DepositStore> DepositStore_Ptr = (ITextureRD_2D *)ITextureRD_2D_Ptr;
    Smart_Ptr<IDDDeposit> IDDDeposit_Ptr = GetDeposit(DepositStore_Ptr);

    Smart_Ptr<CDDDeposit> CDDDeposit_Ptr(NULL);
    if(IDDDeposit_Ptr.isNULL())
    {
      const unsigned char **Mipmaps; 
      const unsigned int *WidthHeight; 
      unsigned int LevelNum;

      if(GetMipmap(&Mipmaps,&WidthHeight,&LevelNum, ITextureRD_2D_Ptr))
      {
        LPDIRECT3DTEXTURE9 pTexture;

        // 產生貼圖物件
        if ( D3D_OK == pDEVICE9->CreateTexture(WidthHeight[0], WidthHeight[1], 
            LevelNum, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &pTexture, NULL) )
        {
          for(unsigned int n = 0; n < LevelNum; ++n)
          {
            // 拷具貼圖資料
            D3DLOCKED_RECT locked_rect;
            pTexture->LockRect(n, &locked_rect, NULL, 0);
            unsigned char *target = (unsigned char *)locked_rect.pBits;
            const unsigned char *source = Mipmaps[n];

            for ( int y=0; y<WidthHeight[n*2+1]; ++y )
            {
              for ( int x=0; x<WidthHeight[n*2]; ++x )
              {
                // D3DFMT_A8R8G8B8的記憶體排列順序是BGRA
                // 要對用 RGBA 排列的記憶體做轉換
                target[0] = source[2];
                target[1] = source[1];
                target[2] = source[0];
                target[3] = source[3];

                target+=4;
                source+=4;
              }
            }
            pTexture->UnlockRect(n);
          }
        }

        CDDDeposit_Ptr = new CDDDeposit(pTexture);
        SetDeposit((CDDDeposit *)CDDDeposit_Ptr, DepositStore_Ptr);
      }
    }
    else
      CDDDeposit_Ptr = (CDDDeposit *)IDDDeposit_Ptr->GetInstance();

    UnLock(IRenderDatagram_Arg);

    if(CDDDeposit_Ptr.isNULL() == false)
    {
      unsigned char vMipmapMode;   // 貼圖的 Mipmap 模式  0:None(內定) 1:Bilinear 2:Trilinear 3:Anisotropic filter

      // 自動產生貼圖座標
      // 參數以 D3D9 的 D3DTSS_TCI 為功能基準
      // 0:以頂點在 View 座標系中的 x,y 值作為貼圖的 u,v，頂點的 z 值不使用，內定值(CAMERASPACEPOSITION)
      // 1:以頂點在 View 座標系中的 法向量值 作為貼圖的座標值(CAMERASPACENORMAL)
      // 2:以 反射向量值 作為貼圖的座標值，其值在 View 座標系中的頂點位置和法向量來計算(CAMERASPACEREFLECTIONVECTOR)
      // 3:以頂點在 View 座標系中 法向量的 x,y 值轉換到 [0,1] 區間，作為貼圖的座標值(SPHEREMAP)
      // -1:不使用自動產生貼圖座標
      char vAutoTexCoordIndexMode;

      unsigned char vTextureAddrMode; // 設定貼圖座標模式  0:Repeat(內定) 1:Mirror 2:ClampEdge 3:ClampBorder
      unsigned int vTextureClampBorderRGBA;      // m_bTextureAddrMode 指定為 ClampBorder 時，所用的顏色，內定為 0,0,0,0

      unsigned char vBlendMode;
      CSmart_Ptr<const C3DMatrix4x4> vTextureMatrix_cPtr(NULL);

      GetAttr(vTextureAddrMode,vTextureClampBorderRGBA,vMipmapMode,vBlendMode,vTextureMatrix_cPtr, vAutoTexCoordIndexMode, ITextureRD_2D_Ptr);

      if(vAutoTexCoordIndexMode != -1)
      {
        if(AutoTexCoordIndexMode(vAutoTexCoordIndexMode, pDEVICE9, m_IStageDDD3D9_Ptr) == false)
          return true; // 不畫出
      }
      else
      {
        Smart_Ptr<IVertexDD> IVertexDD_Ptr = m_IVertexRegistryDDD3D9_Ptr->Get();
        if(IVertexDD_Ptr->SetCoordIndex(pDEVICE9) == false)
        {
          return true; // 不畫出
        }
      }

      TextureAddrMode(vTextureAddrMode, vTextureClampBorderRGBA, pDEVICE9,m_IStageDDD3D9_Ptr);
      TextureMipmapMode(vMipmapMode, pDEVICE9, m_IStageDDD3D9_Ptr);
      BlendMode(vBlendMode, pDEVICE9, m_IStageDDD3D9_Ptr);
      TextureMatrix(vTextureMatrix_cPtr, pDEVICE9, m_IStageDDD3D9_Ptr);

      // 套用貼圖
      pDEVICE9->SetTexture(m_IStageDDD3D9_Ptr->GetStage(), CDDDeposit_Ptr->GetTextureID()); 
    }
    
    return true;
  }
public:
  // Constructor
  CTextureDD_2D_D3D9()
    :cxxlObject(Spirit_Easy),
    m_IStageDDD3D9_Ptr(NULL,this),
    m_IVertexRegistryDDD3D9_Ptr(NULL,this)
  {
  }

  // Destructor
  ~CTextureDD_2D_D3D9()
  {
  }

};

cxxlObject *cxxlFASTCALL New_CTextureDD_2D_D3D9()
{
  return new CTextureDD_2D_D3D9;
}